﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

/// <summary>
/// Summary description for ImageUploader
/// </summary>
public class ImageUploader
{
    private const string dateFormat = "yyyyMMddHHmmss";

    private string[] fileTypes = new string[] { "image/jpeg", "image/png", "image/gif", "image/pjpeg" };
    private int fileSize = 3 * 1024 * 1024; // 3Mb
    private int fileQuality = 89;
    
    public string DestinationPath { get; set; }

    public ImageUploader(string destPath)
    {
        DestinationPath = destPath;
    }

    public string Upload(HttpPostedFile file, Size size)
    {
        if (!IsFileSizeValid(file))
        {
            throw new ArgumentException("File size exceeds allowed size.", "file");
        }

        if (!IsFileTypeAllowed(file))
        {
            throw new ArgumentException("File type not allowed.", "file");
        }
    
        string filename;

        do
        {
            filename = GetFilename(file);
        }
        while (File.Exists(Path.Combine(DestinationPath, filename)));

        try
        {
            using (Image image = new Bitmap(file.InputStream))
            using (Image resized = Resize(image, size))
            {
                Save(resized, filename, fileQuality);

                return filename;
            }
        }
        catch (Exception ex)
        {
            throw new Exception("An error occured during file upload", ex);
        }
    }

    // public string Upload (HttpPostedFile file, Size size) ContentType = "application/x-shockwave-flash"

    public string Upload(HttpPostedFile file)
    {
        if (!IsFileSizeValid(file))
        {
            throw new ArgumentException("File size exceeds allowed size.", "file");
        }

        string filename;

        do
        {
            filename = GetFilename(file);
        }
        while (File.Exists(Path.Combine(DestinationPath, filename)));

        try
        {
            file.SaveAs(Path.Combine(DestinationPath, filename));

            return filename;
        }
        catch (Exception ex)
        {
            throw new Exception("An error occured during file upload", ex);
        }
    }

    public bool IsFileSizeValid(HttpPostedFile file)
    {
        return file.ContentLength <= fileSize;
    }

    public bool IsFileTypeAllowed(HttpPostedFile file)
    {
        return Array.Exists(fileTypes, (s => s.ToLowerInvariant() == file.ContentType.ToLowerInvariant()));
    }

    private static string GetFilename(HttpPostedFile file)
    {
        return string.Format("{0}{1}", DateTime.Now.ToString(dateFormat), Path.GetExtension(file.FileName));
    }

    private void Save(Image image, string filename, int quality)
    {
        using(EncoderParameters ep = new EncoderParameters())
        {
            ep.Param[0] = new EncoderParameter(Encoder.Quality, (long)quality);

            ImageCodecInfo ici = ImageCodecInfo.GetImageEncoders().First(i => i.MimeType.ToLowerInvariant() == "image/jpeg");

            image.Save(Path.Combine(DestinationPath, filename), ici, ep);
        }
    }

    private Image Resize(Image image, Size size)
    {
        if (image.Width < size.Width && image.Height < size.Height)
        {
            size.Width = image.Width;
            size.Height = image.Height;
        }

        Image resized = new Bitmap(size.Width, size.Height);

        using (Graphics g = Graphics.FromImage(resized))
        {
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            g.DrawImage(image, new Rectangle(Point.Empty, size));
        }

        return resized;
    }
}
